/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 battlefield_cell.cpp

	$Header: /heroes4/battlefield_cell.cpp $

	$NoKeywords: $

 ************************************************************************/
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "battlefield_cell.h"

#include "abstract_tile.h"
#include "combat_creature.h"
#include "stationary_combat_object.h"
#include "terrain.h"

static int const k_cell_save_version = 1;

// -----------------------------------------------------------------------
// t_battlefield_cell members
// -----------------------------------------------------------------------

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
t_battlefield_cell::t_battlefield_cell()
	:	m_terrain_type( k_terrain_grass ),
		m_terrain_subtype( 0 )
{
	m_is_quicksand = false;
	m_has_brush = false;
	m_forbidden = false;
	m_forbidden_by_preset = false;
	m_is_obscured = false;
	m_has_gate = false;
	m_obstacle_allowed = true;
}

// -----------------------------------------------------------------------
// add an actor's threat cell
// -----------------------------------------------------------------------
void t_battlefield_cell::add_threat( t_combat_creature* creature )
{
	m_threats.push_back( creature );
}

// -----------------------------------------------------------------------
// remove an actor from the thread list
// -----------------------------------------------------------------------
void t_battlefield_cell::remove_threat( t_combat_creature* actor )
{
	t_combat_creature_list::iterator index;

	for (index = m_threats.begin(); index != m_threats.end(); index++)
		if (index->get() == actor)
		{
			m_threats.erase( index );
			return;
		}
}

// -----------------------------------------------------------------------
// check if cell contains quicksand
// -----------------------------------------------------------------------
void t_battlefield_cell::update_obstacles()
{
	t_combat_object_list::iterator index;

	m_is_quicksand = false;
	m_has_brush = false;
	for (index = m_objects.begin(); index != m_objects.end(); index++)
	{
		if (index->get()->is_quicksand())
			m_is_quicksand = true;
		if (index->get()->hinders_movement())
			m_has_brush = true;
		if (index->get()->obscures_vision())
			m_is_obscured = true;
	}
}


// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
void t_battlefield_cell::set_terrain_type(
	t_terrain_type	new_terrain_type,
	int				new_terrain_subtype )
{
	assert( new_terrain_type >= 0 && new_terrain_type < k_terrain_count );
	assert( new_terrain_subtype >= 0 && new_terrain_subtype < get_terrain_subtype_count( new_terrain_type ) );

	m_terrain_type = new_terrain_type;
	m_terrain_subtype = new_terrain_subtype;
}

// -----------------------------------------------------------------------
// add an object to the cell
// -----------------------------------------------------------------------
void t_battlefield_cell::add( t_abstract_combat_object* object )
{
	m_objects.push_back( object );
	update_obstacles();
}

// -----------------------------------------------------------------------
// get the first actor in the cell.  Check later for dead, etc.
// -----------------------------------------------------------------------
t_combat_creature* t_battlefield_cell::get_creature() const
{
	t_combat_object_list::const_iterator result;
	t_combat_creature*                   actor;

	for (result = m_objects.begin(); result != m_objects.end(); result++)
	{
		actor = dynamic_cast<t_combat_creature*>(result->get());
		if (actor == 0)
			continue;
		if (actor->get_number() == 0)
			continue;
		return actor;
	}
	return 0;
}

// -----------------------------------------------------------------------
// get the tower (if any) in the cell
// -----------------------------------------------------------------------
t_stationary_combat_object* t_battlefield_cell::get_obstacle() const
{
	t_combat_object_list::const_iterator result;
	t_stationary_combat_object*			 object;

	for (result = m_objects.begin(); result != m_objects.end(); result++)
	{
		object = dynamic_cast<t_stationary_combat_object*>(result->get());
		if (object == 0)
			continue;
		return object;
	}
	return 0;
}

// -----------------------------------------------------------------------
// get the tower (if any) in the cell
// -----------------------------------------------------------------------
t_stationary_combat_object* t_battlefield_cell::get_obstacle( t_obstacle_type type ) const
{
	t_combat_object_list::const_iterator result;
	t_stationary_combat_object*			 object;

	for (result = m_objects.begin(); result != m_objects.end(); result++)
	{
		object = dynamic_cast<t_stationary_combat_object*>(result->get());
		if (object == 0 || object->get_obstacle_type() != type )
			continue;
		return object;
	}
	return 0;
}

// -----------------------------------------------------------------------
// get the first attackable object (rock or living creature) in the cell.
// "can be attacked" ensures that the creature is alive, not a body.
// -----------------------------------------------------------------------
t_abstract_combat_object* t_battlefield_cell::get_attackable_object() const
{
	t_combat_object_list::const_iterator result;
	t_abstract_combat_object*			 object;

	for (result = m_objects.begin(); result != m_objects.end(); result++)
	{
		object = *result;
		if (object->get_attackable_object() != 0 && object->can_be_attacked())
			return object;
	}
	return 0;
}


// -----------------------------------------------------------------------
// remove an object from the cell
// -----------------------------------------------------------------------
void t_battlefield_cell::remove( t_abstract_combat_object* object )
{
	t_combat_object_list::iterator result;

	for (result = m_objects.begin(); result != m_objects.end(); result++)
	{
		if (result->get() == object)
		{
			m_objects.erase( result );
			update_obstacles();
			return;
		}
	}
}

// -----------------------------------------------------------------------
// remove an object from the cell
// -----------------------------------------------------------------------
bool t_battlefield_cell::is_blocked( t_combat_object_base const* arg,
									 t_combat_object_base const* object_2 ) const
{
	t_combat_object_list::const_iterator object;

	if (m_forbidden)
		return true;

	for (object = m_objects.begin(); object != m_objects.end(); object++)
	{
		if ((*object)->is_underlay())
			continue;
		if (!(*object)->blocks_movement())
			continue;
		if (object->get() == arg || object->get() == object_2 )
			continue;
		return true;
	}
	return false;
}


// -----------------------------------------------------------------------
// remove an object from the cell
// -----------------------------------------------------------------------
bool t_battlefield_cell::is_blocked( t_combat_object_base const* arg ) const
{
	t_combat_object_list::const_iterator object;

	if (m_forbidden)
		return true;
	for (object = m_objects.begin(); object != m_objects.end(); object++)
	{
		if ((*object)->is_underlay())
			continue;
		if (!(*object)->blocks_movement())
			continue;
		if (object->get() == arg)
			continue;
		return true;
	}
	return false;
}

// -----------------------------------------------------------------------
// Return the current version number for ALL battlefield cells
// Static function
// -----------------------------------------------------------------------
t_uint16 t_battlefield_cell::get_save_version()
{
	return k_cell_save_version;
}

// -----------------------------------------------------------------------
// Read
// -----------------------------------------------------------------------
bool t_battlefield_cell::read( std::streambuf& stream, t_uint16 version )
{
	if ( version > k_cell_save_version )
		return false;

	m_terrain_type = get<t_int8>( stream );
	m_terrain_subtype = get<t_int8>( stream );
	m_forbidden = (get<t_int8>( stream ) != 0);

	if ( version >= 1 )
	{
		m_forbidden_by_preset = (get<t_int8>( stream ) != 0);
	}
	else
	{
		m_forbidden_by_preset = false;
	}

	assert( m_has_brush == false );
	assert( m_is_quicksand == false );
	assert( m_is_obscured == false );
	assert( m_has_gate == false );
	assert( m_objects.empty() );
	return true;
}

// -----------------------------------------------------------------------
// Write
// -----------------------------------------------------------------------
bool t_battlefield_cell::write( std::streambuf& stream ) const
{
	put<t_int8>( stream, m_terrain_type );
	put<t_int8>( stream, m_terrain_subtype );
	put<t_int8>( stream, m_forbidden );
	put<t_int8>( stream, m_forbidden_by_preset );
	return true;
}

// -----------------------------------------------------------------------
// t_battlefield_cell_vertex members
// -----------------------------------------------------------------------

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
t_battlefield_cell_vertex::t_battlefield_cell_vertex()
	:	m_height( 0 )
{
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
void t_battlefield_cell_vertex::set_height( int new_height )
{
	assert( new_height >= 0 && new_height <= k_max_tile_vertex_height );
	m_height = new_height;
}

